package org.example.inventory.facade.service;


import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.example.api.goods.constant.GoodsType;
import org.example.api.inventory.request.InventoryRequest;
import org.example.api.inventory.service.InventoryFacadeService;
import org.example.base.response.SingleResponse;
import org.example.inventory.domain.response.InventoryResponse;
import org.example.inventory.domain.service.impl.BlindBoxInventoryRedisService;
import org.example.inventory.domain.service.impl.CollectionInventoryRedisService;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

import static org.example.api.common.constant.CommonConstant.SEPARATOR;
import static org.example.inventory.domain.service.impl.AbstractInventoryRedisService.ERROR_CODE_INVENTORY_NOT_ENOUGH;

@DubboService(version = "1.0.0")
@Slf4j
public class InventoryFacadeServiceImpl implements InventoryFacadeService {
    private static final String ERROR_CODE_UNSUPPORTED_GOODS_TYPE = "UNSUPPORTED_GOODS_TYPE";

    @Autowired
    private CollectionInventoryRedisService collectionInventoryRedisService;

    @Autowired
    private BlindBoxInventoryRedisService blindBoxInventoryRedisService;

    private Cache<String, Boolean> soldOutGoodsLocalCache;

    @PostConstruct
    public void init() {
        soldOutGoodsLocalCache = Caffeine.newBuilder()
                .expireAfterWrite(1, TimeUnit.MINUTES)
                .maximumSize(3000)
                .build();
    }

    @Override
    public SingleResponse<Boolean> decrease(InventoryRequest inventoryRequest) {
        GoodsType goodsType = inventoryRequest.getGoodsType();
        // 先查询本地缓存
        if (soldOutGoodsLocalCache.getIfPresent(goodsType + SEPARATOR + inventoryRequest.getGoodsId()) != null) {
            return SingleResponse.fail(ERROR_CODE_INVENTORY_NOT_ENOUGH, "库存不足");
        }
        InventoryResponse inventoryResponse = switch (goodsType) {
            case COLLECTION -> collectionInventoryRedisService.decrease(inventoryRequest);

            case BLIND_BOX -> blindBoxInventoryRedisService.decrease(inventoryRequest);

            default -> throw new UnsupportedOperationException(ERROR_CODE_UNSUPPORTED_GOODS_TYPE);
        };
        //1、如果库存为0，则在本地缓存记录，用于对售罄商品快速决策
        //2、当前库存已经是0了，本次扣减失败的情况
        if (isSoldOut(inventoryResponse)) {
            soldOutGoodsLocalCache.put(goodsType + SEPARATOR + inventoryRequest.getGoodsId(), true);
        }
        if (!inventoryResponse.getSuccess()) {
            return SingleResponse.fail(inventoryResponse.getResponseCode(), inventoryResponse.getResponseMessage());
        }
        return SingleResponse.of(true);
    }

    private static boolean isSoldOut(InventoryResponse inventoryResponse) {
        if(inventoryResponse.getSuccess() && inventoryResponse.getInventory() == 0){
            //这部分代码没有实际功能作用，仅用于日志埋点，方便压测时判断延时，详见压测相关视频
            log.warn("debug:soldOut ...");
        }
        return inventoryResponse.getSuccess() && inventoryResponse.getInventory() == 0
                || !inventoryResponse.getSuccess() && inventoryResponse.getResponseCode().equals(ERROR_CODE_INVENTORY_IS_ZERO);
    }
}
